package com.mjk.common.util;

import com.mjk.common.tools.logger.BizLogger;
import org.apache.commons.lang.time.DateUtils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 时间工具类
 * 
 * @author mjk
 * @date 2019年1月16日
 */
public class TimeUtils {
    public static final String DATE_YEAR_TIME = "yyyy";
    public static final String DATE_MONTH = "MM";
    public static final String DATE_MONTH_TIME = "MMdd";
	public static final String DATE_FORMAT_TIME = "HH:mm:ss";
    public static final String DATE_FORMAT_SHORT_TIME = "HHmmss";
    public static final String DATE_FORMAT_TIME_SHORT = "HH:mm";
	public static final String DATE_FORMAT_DATEONLY = "yyyy-MM-dd";
    public static final String DATE_FORMAT_DATEPOINT = "yyyy.MM.dd";
	public static final String DATE_FORMAT_DATETIME = "yyyy-MM-dd HH:mm:ss";
    public static final String DATE_FORMAT_DATETIME_T = "yyyy-MM-ddTHH:mm:ss";
    public static final String DATE_FORMAT_DATETIME_FULL = "yyyy-MM-dd HH:mm:ss.SSS";

    public static final String DATE_FORMAT_DATEMIN = "yyyy-MM-dd HH:mm";
    public static final String DATE_FORMAT_DATETIME_SHORT = "yyyyMMddHHmmss";
    public static final String DATE_FORMAT_DATETIME_SHORT_MI = "yyyyMMddHHmmsssss";
    public static final String DATE_FORMAT_DATEANDMON = "yyyyMM";
    public static final String DATE_FORMAT_DATEANDONEMON = "yyyyM";
	public static final String DATE_FORMAT_DATEANDMON_BS = "yyyy-MM";
	public static final String DATE_FORMAT_YEARDATEANDMON = "yyyyMMdd";
	public static final String DATE_FORMAT_YEARDATEANDMONHORE = "yyyyMMddHH";
    public static final String DATE_FORMAT_YEARDATEANDMON_BS = "yyyy/MM/dd";
    public static final String DATE_FORMAT_DATETIME_BS = "yyyy/MM/dd HH:mm:ss";

    public static final String START_DAY_TIME = " 00:00:00";
    public static final String END_DAY_TIME = " 23:59:59";


    /**
     * 功能：判断字符串是否为日期格式
     * @param strDate  时间字符串
     */
    public static boolean isDate(String strDate) {
        Pattern pattern = Pattern
                .compile("^((\\d{2}(([02468][048])|([13579][26]))[\\-\\/\\s]?((((0?[13578])|(1[02]))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])))))|(\\d{2}(([02468][1235679])|([13579][01345789]))[\\-\\/\\s]?((((0?[13578])|(1[02]))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\\-\\/\\s]?((0?[1-9])|(1[0-9])|(2[0-8]))))))(\\s(((0?[0-9])|([1-2][0-3]))\\:([0-5]?[0-9])((\\s)|(\\:([0-5]?[0-9])))))?$");
        Matcher m = pattern.matcher(strDate);
        return m.matches();
    }

    /**
     * 获取今天是一个月中的第几天
     *
     * @return
     */
	public static int getDayOfMonth() {
        LocalDate data = LocalDate.now();
        return data.getDayOfMonth();
    }

    /**
     * 获取一天的开始时间
     * @param date
     * @return
	 */
	public static Date getDayStart(Date date) {
        LocalDateTime date1 = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
        date1 = date1.withHour(0).withMinute(0).withSecond(0);
        return Date.from(date1.atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * 获取一天的结束时间
     * @param date
     * @return
	 */
	public static Date getDayEnd(Date date) {
        LocalDateTime date1 = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
        date1 = date1.withHour(23).withMinute(59).withSecond(59);
        return Date.from(date1.atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * 获取周一日期
     *
     * @return
     */
    public static String getMondayOfThisWeek() {
        LocalDateTime monday = LocalDateTime.of(LocalDate.now(), LocalTime.MIN).with(DayOfWeek.MONDAY);
        return monday.format(DateTimeFormatter.ofPattern(DATE_FORMAT_DATEONLY));
    }

    /**
     * 获取周日日期
     * @return
     */
	public static String getSundayOfThisWeek() {
        LocalDateTime monday = LocalDateTime.of(LocalDate.now(), LocalTime.MIN).with(DayOfWeek.SUNDAY);
        return monday.format(DateTimeFormatter.ofPattern(DATE_FORMAT_DATEONLY));
    }

    /**
	 * 获取一个月中的第一天
	 * @return
	 */
	public static String getFristDayOfMonth() {
        LocalDate localDate = LocalDate.now().with(TemporalAdjusters.firstDayOfMonth());
        return localDate.format(DateTimeFormatter.ofPattern(DATE_FORMAT_DATEONLY));
    }

    /**
     * 获取一个月的最后一天
     *
     * @return
     */
    public static String getEndDayOfMonth() {
        LocalDate localDate = LocalDate.now().with(TemporalAdjusters.lastDayOfMonth());
        return localDate.format(DateTimeFormatter.ofPattern(DATE_FORMAT_DATEONLY));
	}

	public static LocalDate getTomDay() {
        return getAfterDay(1);
	}

	/**
	 *
	 * @param moth
	 * @return
	 */
    public static String getAfterMoth(int moth) {
        LocalDate localDate = LocalDate.now();
        if (moth > 0) {//如果大于0，则表示往后推，反之往前
            return localDate.plusMonths(moth).format(DateTimeFormatter.ofPattern(DATE_FORMAT_DATEANDMON_BS));
        } else {
            return localDate.minusMonths(-moth).format(DateTimeFormatter.ofPattern(DATE_FORMAT_DATEANDMON_BS));
        }
    }

    /**
     * 获取几天之后的日期
     *
     * @param day
     * @return
     */
    public static LocalDate getAfterDay(int day) {
        LocalDate localDate = LocalDate.now();
        if (day > 0) {//如果大于0，则表示往后推，反之往前
            return localDate.plusDays(day);
        } else {
            return localDate.minusDays(-day);
        }
    }

    /**
     * 获取某天之后几天的日期
     *
     * @param day
     * @param startTime
     * @return
     */
    public static LocalDate getAfterDay(int day, String startTime) {
        LocalDate date = LocalDate.parse(startTime, DateTimeFormatter.ofPattern(DATE_FORMAT_DATEONLY));
        if (day > 0) {//如果大于0，则表示往后推，反之往前
            return date.plusDays(day);
        } else {
            return date.minusDays(-day);
        }
    }

    /**
     * 获取下一个月
     *
     * @return
     */
    public static LocalDate getNextMonth() {
        LocalDate date = LocalDate.now();
        return date.plusMonths(1);
    }

    /**
     * 判断两个日期相差几天
     *
     * @param startDay
     * @param endDay
     * @return
     */
    public static long dateDifference(String startDay, String endDay) {
        LocalDate start = LocalDate.parse(startDay, DateTimeFormatter.ofPattern(DATE_FORMAT_DATEONLY));
        LocalDate end = LocalDate.parse(endDay, DateTimeFormatter.ofPattern(DATE_FORMAT_DATEONLY));
        return end.toEpochDay() - start.toEpochDay();
	}

	/**
	 * 一个日期是否在 时间区域内
	 * @param startTime
	 * @param endTime
	 * @param nowTime
	 * @return
	 */
	public static boolean isBetweenTime(long startTime, long endTime, long nowTime) {
		if ((startTime == 0L) && (endTime == 0L))
			return false;
		if ((startTime != 0L) && (endTime == 0L)) {
            return nowTime >= startTime;
		} else if (startTime == 0L) {
            return nowTime <= endTime;
        } else return (nowTime >= startTime) && (nowTime <= endTime);
    }

    /**
     * 通过生日获取年龄
     *
     * @param birthDay
     * @return
     */
    public static int getAge(String birthDay) {
        LocalDate currentDate = LocalDate.now();
        Double  numberOfMonths = ChronoUnit.MONTHS.between(LocalDate.parse(birthDay, DateTimeFormatter.ofPattern(DATE_FORMAT_DATEONLY)), currentDate) / 12.0;
        return numberOfMonths.intValue();
	}
	
	public static Date parse(String formate, String str) {
		try {
			SimpleDateFormat mate = new SimpleDateFormat(formate);
			return mate.parse(str);
		} catch (ParseException e) {
           BizLogger.error(e);
        }
		return null;
	}
	/**
	 * 获取当前周七天的日期
     */
	public static List<String> getCurrentWeekDays(){
		List<String> weekDays = new ArrayList<>();
		Calendar calendar = Calendar.getInstance();
		  while (calendar.get(Calendar.DAY_OF_WEEK) != Calendar.MONDAY) {
	            calendar.add(Calendar.DATE, -1);
	      }
		  for (int i = 0; i < 7; i++) {
			    weekDays.add(formatTime(calendar.getTime(), DATE_FORMAT_DATEONLY));
	            calendar.add(Calendar.DATE, 1);
	      }
		  return weekDays;
	}
	
	public static SimpleDateFormat getFormat(String pattern) {
		return new SimpleDateFormat(pattern);
	}

	public static String formatTime(Date date, String patternStr) {
		if ((ObjectUtils.isNotEmpty(date)) && (ObjectUtils.isNotEmpty(patternStr))) {
			SimpleDateFormat simpleDateFormat = getFormat(patternStr);
            return simpleDateFormat.format(date);
        }
        return null;
    }


    /**
     * 获取当前日期是星期几<br>
     *
     * @return 当前日期是星期几
     */
    public static Integer getWeekOfDate(String time) {
        LocalDate date = LocalDate.parse(time, DateTimeFormatter.ofPattern(DATE_FORMAT_DATEONLY));
		DayOfWeek dayOfWeek = date.getDayOfWeek(); // 获取星期几
        return dayOfWeek.getValue();
    }

    /**
     * 添加授权时间 1年
     */
    public static String addLicense(String str, int month) {
        LocalDate date = LocalDate.parse(str, DateTimeFormatter.ofPattern(DATE_FORMAT_YEARDATEANDMON));
        return date.plusMonths(month).format(DateTimeFormatter.ofPattern(DATE_FORMAT_YEARDATEANDMON));
    }

    public static Date parse(String str) {
        try {
            return DateUtils.parseDate(str, new String[]{"EEE MMM dd HH:mm:ss zzz yyyy", DATE_FORMAT_DATETIME, DATE_FORMAT_DATETIME_FULL, DATE_FORMAT_DATETIME_T
                    , DATE_FORMAT_DATEONLY, DATE_FORMAT_DATETIME_BS,DATE_FORMAT_YEARDATEANDMON_BS,DATE_FORMAT_YEARDATEANDMON, DATE_FORMAT_TIME, DATE_FORMAT_TIME_SHORT});
        } catch (Exception e){
			return null;
		}
	}
	
	public static long differenceTime(String startTime, String endTime) {
        return differenceTime(startTime, endTime, DATE_FORMAT_DATETIME);
	}
	
	public static int differenceMonth(String startTime,String endTime){
		return differenceMonth(startTime,endTime,DATE_FORMAT_DATEONLY);
	}
	/**
     * 获取两个日期相差的月数
     */
    public static int differenceMonth(String startTime,String endTime,String formatstr) {
    	try{
	    	SimpleDateFormat format = new SimpleDateFormat(formatstr);
	        Calendar c1 = Calendar.getInstance();
	        Calendar c2 = Calendar.getInstance();
	        c1.setTime(format.parse(startTime));
	        c2.setTime(format.parse(endTime));
	        int year1 = c1.get(Calendar.YEAR);
	        int year2 = c2.get(Calendar.YEAR);
	        int month1 = c1.get(Calendar.MONTH);
	        int month2 = c2.get(Calendar.MONTH);
	        int day1 = c1.get(Calendar.DAY_OF_MONTH);
	        int day2 = c2.get(Calendar.DAY_OF_MONTH);
	        // 获取年的差值 
	        int yearInterval = year1 - year2;
	        // 如果 d1的 月-日 小于 d2的 月-日 那么 yearInterval-- 这样就得到了相差的年数
	        if (month1 < month2 || month1 == month2 && day1 < day2) {
	            yearInterval--;
	        }
	        // 获取月数差值
	        int monthInterval = (month1 + 12) - month2;
	        if (day1 < day2) {
	            monthInterval--;
	        }
	        monthInterval %= 12;
            return Math.abs(yearInterval * 12 + monthInterval);
    	}catch(Exception e){
    		return 0;
    	}
    }
	
	public static long differenceTime(String startTime,String endTime,String formatstr){
		//时间格式，自己可以随便定义
        SimpleDateFormat format = new SimpleDateFormat(formatstr);
        //一天的毫秒数
        long nd = 1000*60*60*24L;
        //一小时的毫秒数
        long nh = 1000*60*60L;
        //一分钟的毫秒数
        long nm = 1000*60L;
        //一秒钟的毫秒数
        //long ns = 1000L;
        long diff = 0;
        try{
            //获取两个时间的毫秒时间差
            diff = format.parse(endTime).getTime() - format.parse(startTime).getTime();
        }catch (Exception e) {
			BizLogger.error(e);
        }
        //计算相差的天数
        long day = diff/nd;
        //计算相差的小时
        long hour = diff%nd/nh;
        //计算相差的分钟
        long min = diff%nd%nh/nm;
        //计算相差的秒2
        //long sec = diff%nd%nh%nm/ns;
        return day*24+hour+min/30;
    }
	
	/**
	 * 获取一年内所有双休日
     */
	public static Set<String> getYearWeekdays(String year){
			 Set<String> listDates = new HashSet<>();
			 Calendar calendar=Calendar.getInstance();//当前日期
			  calendar.set(Integer.parseInt(year), Calendar.JULY, 1);
			  Calendar nowyear=Calendar.getInstance();
			  Calendar nexty=Calendar.getInstance();
			  nowyear.set(Integer.parseInt(year), Calendar.JANUARY, 1);//2010-1-1
			  nexty.set(Integer.parseInt(year)+1, Calendar.JANUARY, 1);//2011-1-1
			  calendar.add(Calendar.DAY_OF_MONTH, -calendar.get(Calendar.DAY_OF_WEEK));//周六
			  Calendar c=(Calendar) calendar.clone();
			 for(;calendar.before(nexty)&&calendar.after(nowyear);calendar.add(Calendar.DAY_OF_YEAR, -7)){
				  String month = StrUtils.addZero((1+calendar.get(Calendar.MONTH))+"",2);
				  listDates.add(calendar.get(Calendar.YEAR)+"-"+month+"-"+StrUtils.addZero(calendar.get(Calendar.DATE)+"",2));
				  listDates.add(calendar.get(Calendar.YEAR)+"-"+month+"-"+StrUtils.addZero((1+calendar.get(Calendar.DATE)+""),2));
			  }
			for(;c.before(nexty)&&c.after(nowyear);c.add(Calendar.DAY_OF_YEAR, 7)){
				String month = StrUtils.addZero((1+c.get(Calendar.MONTH))+"",2);
				 listDates.add(c.get(Calendar.YEAR)+"-"+month+"-"+StrUtils.addZero(c.get(Calendar.DATE)+"",2));
				 listDates.add(c.get(Calendar.YEAR)+"-"+month+"-"+StrUtils.addZero((1+c.get(Calendar.DATE)+""),2));
			  }
			  return listDates;
		 }
	public static class TimeSearch {
		public static final String START_TIME = "start";
		public static final String END_TIME = "end";
	}

}